#ifndef SENDERO_H
#define SENDERO_H

#include "Grilla.h"
#include "Camino.h"

class Sendero
    {
    private: 

        unsigned int filas;
        unsigned int columnas;
        bool** matriz;
		unsigned int factorMapeo ;

		void inicializarSendero(Grilla* grilla, unsigned int unFactorMapeo)
			{
            this->factorMapeo = unFactorMapeo ;
            // la cantidad por la que se multiplica despues hay que parametrizarla.
            this->filas = this->factorMapeo * grilla->getFilas();
            this->columnas = this->factorMapeo * grilla->getColumnas();

            /*
            Reserva de Memoria para la matriz del escenario.
            */
            this->matriz = (bool**)malloc(this->filas*sizeof(bool*));
            for(unsigned int i=0;i<this->filas;i++)
                this->matriz[i] = (bool*)malloc(this->columnas*sizeof(bool));
            
            // Inicializo toda la mariz en false.
            for(unsigned int i = 0; i < this->filas; i++)
                {
                for(unsigned int j = 0; j < this->columnas; j++)
                    {
                    this->matriz[i][j] = false;
                    }
                }

			
			unsigned int ptoMedio = (unsigned int)floor((float)(this->factorMapeo)/(float)(2));
			unsigned int posAux ;
            //Se colocan primero todos los camino horiz
            for(unsigned int i = 0; i < this->filas; i ++ ){
                for(unsigned int j = ptoMedio ; j < this->columnas; j = j + this->factorMapeo ){
                    int fila = (int)floor((float)i / (float)this->factorMapeo) ;
                    int columna = (int)floor((float)j / (float)this->factorMapeo) ;
                    if(grilla->getCasillero(fila,columna)->getContenido()->esCamino()){
						
						posAux = i - ((unsigned int)fila  * this->factorMapeo);

						// Si son los puntos de arriba verifico que exista algo arriba
						if( posAux >=0 && posAux < ptoMedio ){
							if(((Camino*)(grilla->getCasillero(fila,columna)->getContenido()))->hayCaminoArriba())
								this->matriz[i][j] = true;
						// Si son los puntos de abajo verifico que exista algo abajo
						}else if ( posAux > ptoMedio && posAux <= (this->factorMapeo -1) ) {
							if(((Camino*)(grilla->getCasillero(fila,columna)->getContenido()))->hayCaminoAbajo())
								this->matriz[i][j] = true;
						}
                    }
                }
             }

            //Se colocan los caminos vert.
             for(unsigned int i = 0; i < this->columnas; i ++ ){
                for(unsigned int j = ptoMedio; j < this->filas; j = j + this->factorMapeo){
                    int columna = (int)floor((float)i / (float)this->factorMapeo) ;
                    int fila = (int)floor((float)j / (float)this->factorMapeo) ;
                    if(grilla->getCasillero(fila,columna)->getContenido()->esCamino()){
						
						posAux = i - ((unsigned int)columna  * this->factorMapeo);
						// Si son los puntos de izq verifico que exista algo a la izq
						if( posAux >=0 && posAux < ptoMedio ){
							if(((Camino*)(grilla->getCasillero(fila,columna)->getContenido()))->hayCaminoIzquierda())
								this->matriz[j][i] = true;
						// Si son los puntos de la derecha verifico que exista algo a la der
						}else if ( posAux > ptoMedio && posAux <= (this->factorMapeo -1) ) {
							if(((Camino*)(grilla->getCasillero(fila,columna)->getContenido()))->hayCaminoDerecha())
								this->matriz[j][i] = true;
						} else if (posAux == ptoMedio){
							this->matriz[j][i] = true;
						}	
                    }
                }
             }


            }

	
	public:

		Sendero(Grilla* grilla)
			{
				unsigned int factorDefecto = 3 ;

				this->inicializarSendero(grilla, factorDefecto);
			}

        Sendero(Grilla* grilla, unsigned int unFactorMapeo)
			{
				this->inicializarSendero(grilla, unFactorMapeo);
			}

		unsigned int getFactorMapeo(){
			return this->factorMapeo ; 
		}


        bool perteneceAlSendero(Punto* punto){
			if(punto->getX() >= 0 && punto->getX() < this->columnas && 
				punto->getY() >= 0 && punto->getY() < this->filas ){
				return this->matriz[punto->getY()][punto->getX()];					
			}else{
				return false;
			}
        }

		// Retorna coordenadas correspondientes a la grilla
		Punto* getPuntoGrilla(Punto* puntoSendero){
			unsigned int nuevoX = (unsigned int)floor((float)puntoSendero->getX() / (float)this->factorMapeo);
			unsigned int nuevoY = (unsigned int)floor((float)puntoSendero->getY() / (float)this->factorMapeo);
			Punto* p = new Punto(nuevoX,nuevoY);
			return p;
		
		}

		// Dado un punto en la grilla retorna el punto en el sendero (el de el medio)
		Punto* getPuntoSenderoConPuntoGrilla(Punto* puntoGrilla){
			return this->getPuntoSenderoConPuntoGrilla(puntoGrilla->getX(),puntoGrilla->getY());
		}

		// Dado un punto en la grilla retorna el punto en el sendero (el de el medio)
		Punto* getPuntoSenderoConPuntoGrilla(int x, int y){
			unsigned int factor = this->getFactorMapeo();
			unsigned int mitadFactor  = (unsigned int)floor((float)factor/(float)2) ;
			Punto* puntoSendero = new Punto(mitadFactor+factor*(unsigned int)x,mitadFactor+factor*(unsigned int)y);
			return puntoSendero ;
		}

		// Para facilitar el calculo del radio, es la mitad del factor mapeo
		int getRadioStandard(){
			return (unsigned int)floor((float)this->getFactorMapeo()/(float)2) ;
		}

        ~Sendero(void){
			for(int i=0;i<this->filas;i++){
				free(this->matriz[i]);
			}
			free(this->matriz);
            
		}
		string toString(){
			string res;
			for(unsigned int i = 0; i < this->filas; i++){
                for(unsigned int j = 0; j < this->columnas; j++){
					if(this->matriz[i][j]){
						res = res + "1 ";
					}else{
						res = res + "0 ";
					}
                }
				res = res + "\n";
            }
			res = res + "\n\n";

			return res ;
		
		}
    };
#endif
